package com.kingsoft.miot.bridge.utils;

//import com.xiaomi.miot.bridge.exception.CommonErrorCode;
//import com.xiaomi.miot.bridge.exception.ExceptionHelper;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 签名的生成，就是按照下面的代码产生，如果你的代码能生成同样的签
 * 名，你的实现就是正确的了。（不说废话，代码最精确） 签名用ECDSA算法
 * 
 * @author HUJIANQING
 *
 */
public class ECDSAUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(ECDSAUtil.class);
	public static final String KEY_ALGORITHM = "EC";
	public static final String SIGNATURE_ALGORITHM = "SHA256withECDSA";
	private static final int KEY_SIZE = 256;

	public static class ECDSAKeys {
		private byte[] publicKey;
		private byte[] privateKey;

		public byte[] getPublicKey() {
			return publicKey;
		}

		public byte[] getPrivateKey() {
			return privateKey;
		}
	}

	public static ECDSAKeys genKeyPair() {
		KeyPairGenerator keyPairGenerator = null;
		try {
			keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		} catch (NoSuchAlgorithmException e) {
			LOGGER.error("failed to create pair, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		}
		keyPairGenerator.initialize(KEY_SIZE);
		KeyPair keyPair = keyPairGenerator.generateKeyPair();

		ECDSAKeys pairKeys = new ECDSAKeys();
		pairKeys.privateKey = keyPair.getPrivate().getEncoded();
		pairKeys.publicKey = keyPair.getPublic().getEncoded();

		return pairKeys;
	}

	/**
	 * 
	 * @param data
	 * @param privateKey
	 * @return
	 */
	public static String signWithStr(byte[] data, String privateKey) {
		byte[] signBin = sign(data, Base64.decodeBase64(privateKey));
		return Base64.encodeBase64URLSafeString(signBin);
	}

	public static byte[] sign(byte[] data, byte[] privateKey) {
		PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initSign(priKey);
			signature.update(data);
			return signature.sign();

		} catch (NoSuchAlgorithmException e) {
			LOGGER.error("failed to sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (SignatureException e) {
			LOGGER.error("failed to sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (InvalidKeyException e) {
			LOGGER.error("failed to  sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (InvalidKeySpecException e) {
			LOGGER.error("failed to sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		}
		return null;
	}

	/**
	 * 验证公钥私钥是否对等
	 * @param data
	 * @param publicKey
	 * @param signStr
	 * @return
	 */
	public static boolean verify(byte[] data, byte[] publicKey, String signStr) {
		KeyFactory keyFactory;
		try {
			keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
			PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
			Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
			signature.initVerify(pubKey);
			signature.update(data);
			byte[] sign = Base64.decodeBase64(signStr);
			// 验证通过  返回true
			return signature.verify(sign);
		} catch (NoSuchAlgorithmException e) {
			LOGGER.error("failed to verify sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (SignatureException e) {
			LOGGER.error("failed to verify sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (InvalidKeyException e) {
			LOGGER.error("failed to verify sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		} catch (InvalidKeySpecException e) {
			LOGGER.error("failed to verify sign, ", e);
//			throw ExceptionHelper.buildOpFailureException(CommonErrorCode.SystemError, "internal error");
		}
		return false;
	}

}